package org.dxy.domain.handler.material;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dxy.domain.command.material.DeleteMaterialCommand;
import org.dxy.domain.model.aggregate.Material;
import org.dxy.domain.port.repository.IMaterialRepository;
import com.google.common.eventbus.EventBus;
import org.dxy.domain.port.IEventRepository;
import org.dxy.domain.handler.CommandHandler;
import org.dxy.domain.event.DomainEvent;
import org.dxy.domain.exception.DomainException;
import org.dxy.types.common.CommandResult;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.util.ArrayList;
import java.util.List;

/**
 * 删除物料命令处理器
 * @author dxy
 * @createTime 2025/9/7
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class DeleteMaterialCommandHandler implements CommandHandler<DeleteMaterialCommand, Void> {

    private final IMaterialRepository IMaterialRepository;
    private final EventBus eventBus;
    private final IEventRepository eventRepository;

    @Transactional
    @Override
    public CommandResult<Void> handle(DeleteMaterialCommand command) {
        try {
            // 1. 加载物料聚合根
            Material material = IMaterialRepository.findById(command.materialId());
            if (material == null) {
                return CommandResult.fail(null, "物料不存在: " + command.materialId());
            }

            // 2. 执行删除操作
            material.delete(command);

            // 3. 保存物料
            IMaterialRepository.save(material);

            List<DomainEvent> events = material.getDomainEvents();

            // 4. 保存事件到事件存储，获取固定的事件ID列表
            List<Long> eventIds = eventRepository.saveEvents(events);

            // 5. 创建事件副本用于发布
            List<DomainEvent> eventsCopy = new ArrayList<>(events);

            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                @Override
                public void afterCommit() {
                    // 使用事务提交前保存的事件副本
                    eventsCopy.forEach(eventBus::post);
                    // 当事件发布成功后，会把这个字段标记为 true
                    eventRepository.markEventsPublished(eventIds);
                    // 7. 清理事件
                    material.clearDomainEvents();
                }
            });

            log.info("删除物料成功, materialId={}, command={}", command.materialId(), command);
            return CommandResult.success(null, "删除物料成功");
        } catch (DomainException e) {
            return CommandResult.fail(null, e.getMessage()); // 业务错误
        } catch (RuntimeException e) {
            log.error("系统异常", e); // 系统异常
            return CommandResult.fail(null, "系统异常，请稍后重试");
        }
    }
}